#pragma once
#include <functional>
#include <vector>
#include <memory>
#include <cmath>
#include <iostream>
#include <CImg.h>

#include "Common.h"
#include "Primative.h"

class Scene
{
  public:
    Scene(std::function<void (Scene*)> setup) :
      mPrimatives(),
      mCameraOrigin(0.0f, 0.0f, 0.0f),
      mCameraRotation(0.0f, 0.0f, 0.0f),
      mCameraFocalLength(1.0f)
    {
      updateBasis();

      setup(this);
    }

    void add(std::shared_ptr<Primative> addMe)
    {
      mPrimatives.push_back(addMe);
    }

    void setCameraOrigin(const Float3& origin)
    {
      mCameraOrigin = origin;
    }

    void setCameraRotation(const Float3& radians)
    {
      mCameraRotation = radians;
      updateBasis();
    }

    void setCameraFocalLength(const float distance)
    {
      mCameraFocalLength = distance;
    }

    void render(cimg_library::CImg<float>& bitmap, 
                const size_t height, 
                const size_t width);

  private:
    std::vector<std::shared_ptr<Primative>> mPrimatives;
    Float3 mCameraOrigin;
    Float3 mCameraRotation;
    AffineMatrix mCameraTransform;
    float mCameraFocalLength;

    std::shared_ptr<Primative> rayTrace(const Ray& theRay, 
                                        RGBColor& color,
                                        size_t reflectionCount = 0);
    void updateBasis();
    Ray emitRay(float x, float y);
};
